#include <elfparser.h>
#include <stddef.h>

// 30 MB
#define N (0xA00000 * 3)

static char buf[N];

/* 从文件的开头偏移 offset 处开始读取 size 字节数据至 dest */
static void read_file(FILE* fp, size_t offset, size_t size, void* buf) {
	fseek(fp, offset, SEEK_SET);
	size_t nmemb = 1; // nmemb -- 元素的个数, 每个元素的大小为 size 字节
	size_t result = fread(buf, size, nmemb, fp);
	// 如果总数与 nmemb 参数不同, 则可能发生了错误或者到达了文件末尾
	assert(nmemb == result);
}

// /* 读取文件内容到缓冲区 */
// static void read_file_to_buf(FILE* fp, char* buf) {
//     fseek(fp, 0, SEEK_END);
//     size_t file_size = ftell(fp);
//     fseek(fp, 0, SEEK_SET);
//     size_t read_size = fread(buf, 1, file_size, fp);
//     assert(read_size == file_size);
// }

static void append_to_func_table(FuncEntry* func_table, int count, const char* name, size_t start, size_t size, enum LevelType level) {
    strncpy(func_table[count].name, name, FUNC_NAME_MAX_LEN);
    func_table[count].name[FUNC_NAME_MAX_LEN-1] = '\0';
    func_table[count].start = start;
    func_table[count].size = size;
    func_table[count].level = level;
}

int parse_elf(FILE* fp, size_t offset, size_t size, FuncEntry* func_table, enum LevelType level) {
    // read_file_to_buf(fp, buf);
    read_file(fp, offset, size, buf);
    Elf_Ehdr* ehdr = (Elf_Ehdr*)buf;

    /* ********* Section header table ********* */ 
    /* Section header table file offset */
    Elf_Off shoff = ehdr->e_shoff;
    /* Section header table entry count */
    Elf_Half shnum = ehdr->e_shnum;
    /* ********* Section header table ********* */

    /* ********* Section 'symtab' ********* */
    // 遍历 Section header table, 找出符号表 symtab
    Elf_Shdr* symtab_shdr = NULL;
    for (int i = 0; i < shnum; ++i) {
        Elf_Shdr* shdr = (Elf_Shdr*)(buf + shoff) + i;
        if (shdr->sh_type == SHT_SYMTAB) {
            symtab_shdr = shdr;
            break;
        }
    }
    size_t symtab_count = symtab_shdr->sh_size / symtab_shdr->sh_entsize;
    /* Section header 'strtab' (symtab to link) */
    Elf_Shdr* strtab_shdr = (Elf_Shdr*)(buf + shoff) + symtab_shdr->sh_link;
    char* strtab = buf + strtab_shdr->sh_offset;

    Elf_Sym* symtab = (Elf_Sym*)(buf + symtab_shdr->sh_offset);
    int count = 0;
    for (int i = 0; i < symtab_count; ++i) {
        if (ELF64_ST_TYPE(symtab[i].st_info) != STT_FUNC) continue;
        // printf("--> name: %s, value: %#x, size: %u\n", strtab + symtab[i].st_name, symtab[i].st_value, symtab[i].st_size);
        append_to_func_table(func_table, count++, strtab + symtab[i].st_name, symtab[i].st_value, symtab[i].st_size, level);
    }
    /* ********* Section 'symtab' ********* */

    return count;
}
